package wsi.fusion;

import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;

import org.rygh.core.html.table.HtmlTable;
import org.rygh.core.util.counter.CounterTuple;
import org.rygh.core.xml.XmlPath;
import org.rygh.semantic.func.RdfFunctionalityController;
import org.rygh.semantic.gui.swing.input.Input;
import org.rygh.semantic.model.ex.FactSet;
import org.rygh.semantic.model.rdf.Entity;
import org.rygh.semantic.model.rdf.Fact;

import wsi.dataguide.DataGuide;
import wsi.dataguide.tree.WSXmlLeaf;
import wsi.match.MatchPair;
import wsi.match.SubtreeController;
import wsi.resolve.FactItem;

public abstract class Fuser {
	protected final Logger log = Logger.getLogger(getClass().getName());

	protected final RdfFunctionalityController functionalityCtrl = RdfFunctionalityController
			.shared();

	protected final VariableManager variableManager = new VariableManager();
	protected final SubtreeController subtreeController;

	protected boolean inputEqualsToCenter;
	protected Input input;

	protected Fuser(SubtreeController subtreeController) {
		this.subtreeController = subtreeController;
	}

	protected abstract Entity fuse(Entity varEntity, WSXmlLeaf subroot);

	protected String getValue(XmlPath xpath, WSXmlLeaf subroot) {
		WSXmlLeaf obj = null;

		boolean is_sup = !subtreeController.containsCommonRoot(xpath);

		List<WSXmlLeaf> leaves = is_sup ? subtreeController.getSupLeaves(input)
				: subtreeController.getLeaves(subroot);

		if (leaves == null) {
			log.info(String.format(
					"Cannot get value, is_sup %b, xpath %s, root %s", is_sup,
					xpath, subroot.getXpath()));
			return null;
		}

		for (WSXmlLeaf l : leaves) {
			if (xpath.subsumesWithoutIndex(l.getXpath())) {
				obj = l;
				break;
			}
		}

		if (obj == null) {
			// this is normal, some subtrees are incomplete.
			// log.info("[warn] getValue not found at " + xpath.getValue());
			return null;
		}

		String val = obj.getValue().getValue();

		if (val == null || val.trim().isEmpty())
			return null;

		return val.trim();
	}

	public VariableManager getVariableManager() {
		return variableManager;
	}

	public void instantiate(FactSet facts, WSXmlLeaf subroot,
			Collection<CounterTuple<String>> factItems) {
		Entity subj, obj;
		Fact new_fact;

		for (CounterTuple<String> o : factItems) {
			FactItem item = (FactItem) o.getValue();

			// System.out.println("to instantiate facts \n" +
			// item.getFactGroup());

			for (Fact fact : item.getFactGroup()) {
				subj = fuse(fact.getSubject(), subroot);
				obj = fuse(fact.getObject(), subroot);

				if (subj == null || obj == null)
					continue;

				new_fact = new Fact(subj, fact.getPredicate(), obj);

				if (subj.isLiteral() && obj.isLiteral()) {
					log.info("[warn] both subj and obj are literals "
							+ fact.getSubject().getValue() + " fact "
							+ new_fact);

					continue;
				}

				facts.add(new_fact);

				// System.out.println("\t new fact " + new_fact);
			}
		}
	}

	public boolean isInputEqualsToCenter() {
		return inputEqualsToCenter;
	}

	public void prepareVariables(List<MatchPair> pairs, DataGuide dataGuide) {
		WSXmlLeaf dg_leaf, leaf;

		for (MatchPair p : pairs) {
			leaf = p.getXmlLeaf();
			assert !p.getEntityLeaf().isRoot();

			dg_leaf = dataGuide.getIsomorphicLeaf(leaf);
			variableManager.register(dg_leaf, p.isSuperNode());
		}

	}

	public void setInput(Input input) {
		this.input = input;
	}

	public void setInputEqualsToCenter(boolean inputEqualsToCenter) {
		this.inputEqualsToCenter = inputEqualsToCenter;
	}

	public abstract HtmlTable toHtmlTable();
}
